home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / LIBRARY / SHDK_2 / SHLIST.PAS < prev    next >
Pascal/Delphi Source File  |  1992-04-30  |  22KB  |  670 lines

  1. {$I SHDEFINE.INC}
  2.  
  3. {$I SHUNITSW.INC}
  4.  
  5. {$D-,L-}
  6. {$A-,V-}
  7. unit ShList;
  8. {
  9.                                  ShList
  10.  
  11.                          A List Processing Unit
  12.  
  13.                                    by
  14.  
  15.                               Bill Madison
  16.  
  17.                    W. G. Madison and Associates, Ltd.
  18.                           13819 Shavano Downs
  19.                             P.O. Box 780956
  20.                        San Antonio, TX 78278-0956
  21.                              (512)492-2777
  22.                              CIS 73240,342
  23.  
  24.                   Copyright 1991 Madison & Associates
  25.                           All Rights Reserved
  26.  
  27.         This file may  be used and distributed  only in accord-
  28.         ance with the provisions described on the title page of
  29.                   the accompanying documentation file
  30.                               SKYHAWK.DOC
  31. }
  32.  
  33. interface
  34.  
  35. uses
  36.   TpString,
  37.   TpInline,
  38.   TpMemChk;
  39.  
  40. type
  41.   slNodePtr = ^slNode;
  42.   slNode    = record
  43.                 Data  : pointer;
  44.                 Next  : slNodePtr;
  45.                 end;
  46.   dlNodePtr = ^dlNode;
  47.   dlNode    = record
  48.                 Data  : pointer;
  49.                 Next,
  50.                 Prev  : dlNodePtr;
  51.                 end;
  52.   slList    = record
  53.                 DataRecSize : word;
  54.                 Count       : LongInt;
  55.                 Head,
  56.                 Tail,
  57.                 Current     : slNodePtr;
  58.                 end;
  59.   dlList    = record
  60.                 DataRecSize : word;
  61.                 Count       : LongInt;
  62.                 Head,
  63.                 Tail,
  64.                 Current     : dlNodePtr;
  65.                 end;
  66.   dlLessFunc= function(var DataRec1, DataRec2)  : boolean;
  67.  
  68. {******************INITIALIZATION ROUTINES************************}
  69.  
  70. procedure slListInit(var L  : slList; RecSize : word);
  71. {Initializes a singly linked list.}
  72.  
  73. procedure dlListInit(var L : dlList; RecSize : word);
  74. {Initializes a doubly linked list.}
  75.  
  76. {******************STORAGE ROUTINES************************}
  77.  
  78. function slPush(var L : slList; var DataRec) : boolean;
  79. function dlPush(var L : dlList; var DataRec) : boolean;
  80. {Pushes a data record onto the top of the list.}
  81.  
  82. function slAppend(var L : slList; var DataRec) : boolean;
  83. function dlAppend(var L : dlList; var DataRec) : boolean;
  84. {Appends a data record to the tail of the list.}
  85.  
  86. function slPut(var L : slList; var DataRec) : boolean;
  87. function dlPut(var L : dlList; var DataRec) : boolean;
  88. {Inserts a data record following the current node; returns with current
  89.  pointer directed to the new node.}
  90.  
  91. function dlPutPrev(var L : dlList; var DataRec) : boolean;
  92. {Inserts a data record ahead of the current node; returns with current
  93.  pointer directed to the new node.}
  94.  
  95. function dlPutSorted(var L : dlList;
  96.                         var DataRec; Less : dlLessFunc) : boolean;
  97. {Inserts a data record into the list in sorted order, as determined by
  98.  the user-defined boolean function LESS.}
  99.  
  100. procedure slFree(var L : slList);
  101. procedure dlFree(var L : dlList);
  102. {Releases the heap space allocated for a list and re-initializes the
  103.  list.}
  104.  
  105. {******************RETRIEVAL ROUTINES************************}
  106.  
  107. function slGetCurrent(var L : slList; var DataRec) : boolean;
  108. {Returns the data record at the current node and does not move the node
  109.  pointer. Returns a function value of false if the list is empty or the
  110.  current node pointer is nil.}
  111.  
  112. function dlGetCurrent(var L : dlList; var DataRec) : boolean;
  113. {Returns the data record at the current node and does not move the node
  114.  pointer. Returns a function value of false if the list is empty or the
  115.  current node pointer is nil.}
  116.  
  117. function slGetFirst(var L : slList; var DataRec) : boolean;
  118. {Returns the data record at the head of the list. Sets the current node
  119.  pointer to the head of the list. Returns a function value of false if
  120.  the list is empty.}
  121.  
  122. function dlGetFirst(var L : dlList; var DataRec) : boolean;
  123. {Returns the data record at the head of the list. Sets the current node
  124.  pointer to the head of the list. Returns a function value of false if
  125.  the list is empty.}
  126.  
  127. function slGetLast(var L : slList; var DataRec) : boolean;
  128. {Returns the data record at the tail of the list. Sets the current node
  129.  pointer to the tail of the list. Returns a function value of false if
  130.  the list is empty.}
  131.  
  132. function dlGetLast(var L : dlList; var DataRec) : boolean;
  133. {Returns the data record at the tail of the list. Sets the current node
  134.  pointer to the tail of the list. Returns a function value of false if
  135.  the list is empty.}
  136.  
  137. function slGetNext(var L : slList; var DataRec) : boolean;
  138. {Returns the next data record in the list. Sets the current node pointer
  139.  to the record retrieved. Returns a function value of false if the list is
  140.  empty or if the last record successfully retrieved was at the list tail.
  141.  In this case, calling slGetNext again will retrieve the head of the list.}
  142.  
  143. function dlGetNext(var L : dlList; var DataRec) : boolean;
  144. {Returns the next data record in the list. Sets the current node pointer
  145.  to the record retrieved. Returns a function value of false if the list is
  146.  empty or if the last record successfully retrieved was at the list tail.
  147.  In this case, calling dlGetNext again will retrieve the head of the list.}
  148.  
  149. function dlGetPrev(var L : dlList; var DataRec) : boolean;
  150. {Same as dlGetNext, but in the opposite direction.}
  151.  
  152. function slPop(var L : slList; var DataRec) : boolean;
  153. {Returns the data record at the head of the list, then deallocates the
  154.  space associated with the data record and node. Returns a function value
  155.  of false if the list is empty.}
  156.  
  157. function dlPop(var L : dlList; var DataRec) : boolean;
  158. {Returns the data record at the head of the list, then deallocates the
  159.  space associated with the data record and node. Returns a function value
  160.  of false if the list is empty.}
  161.  
  162. {******************GENERAL UTILITY ROUTINES************************}
  163.  
  164. function slCount(L : slList) : LongInt;
  165. {Returns the number of records currently in the list.}
  166.  
  167. function dlCount(L : dlList) : LongInt;
  168. {Returns the number of records currently in the list.}
  169.  
  170. function slSpaceUsed(L : slList) : LongInt;
  171. {Returns the total amount of heap space currently allocated to the list.}
  172.  
  173. function dlSpaceUsed(L : dlList) : LongInt;
  174. {Returns the total amount of heap space currently allocated to the list.}
  175.  
  176. function Ptr2Str(P : pointer) : string;
  177. {This function is included primarily for debugging.}
  178. {Returns a string of the form ssss:oooo being the hex representation of
  179.  the pointer P following normalization, in segment:offset form.}
  180.  
  181. {*******************************************************************}
  182. {*******************************************************************}
  183. implementation
  184. {*******************************************************************}
  185. {*******************************************************************}
  186.  
  187. {******************INTERNAL UTILITY ROUTINES************************}
  188.  
  189. function Ptr2Str(P:pointer) : string; {For debugging only!}
  190.   begin
  191.     Ptr2Str := HexPtr(Normalized(P));
  192.     end;
  193.  
  194. function slGrabMemory(var L : slList;
  195.                       var P : slNodePtr;
  196.                       var DataRec)        : boolean;
  197. {Gets the heap space needed for the node and its data record.}
  198.   begin
  199.     if GetMemCheck(P, SizeOf(slNode)) then begin
  200.       if GetMemCheck(P^.Data, L.DataRecSize) then begin
  201.         slGrabMemory := true;
  202.         Move(DataRec, P^.Data^, L.DataRecSize);
  203.         exit;
  204.         end
  205.       else {room for the node but not the data}
  206.         FreeMemCheck(P, SizeOf(slNode));
  207.       end;
  208.     {If we get to here, there has been a space allocation problem.}
  209.     slGrabMemory := false;
  210.     end;  {slGrabMemory}
  211.  
  212. function dlGrabMemory(var L : dlList;
  213.                       var P : dlNodePtr;
  214.                       var DataRec)        : boolean;
  215. {Gets the heap space needed for the node and its data record.}
  216.   begin
  217.     if GetMemCheck(P, SizeOf(dlNode)) then begin
  218.       if GetMemCheck(P^.Data, L.DataRecSize) then begin
  219.         dlGrabMemory := true;
  220.         Move(DataRec, P^.Data^, L.DataRecSize);
  221.         exit;
  222.         end
  223.       else {room for the node but not the data}
  224.         FreeMemCheck(P, SizeOf(dlNode));
  225.       end;
  226.     {If we get to here, there has been a space allocation problem.}
  227.     dlGrabMemory := false;
  228.     end;  {dlGrabMemory}
  229.  
  230. function slFirstNode(var L : slList; var P : slNodePtr) : boolean;
  231. {If list L is empty and the first node has been allocated, sets up the
  232.  pointers. Assumes that the node has been allocated with slGrabMemory.
  233.  Returns a function value of false if the list is not empty.}
  234.   begin
  235.     L.Current := P;
  236.     if L.Count = 0 then begin
  237.       slFirstNode := true;
  238.       P^.Next := nil;
  239.       L.Head := P;
  240.       L.Tail := P;
  241.       end
  242.     else
  243.       slFirstNode := false;
  244.     end; {slFirstNode}
  245.  
  246. function dlFirstNode(var L : dlList; var P : dlNodePtr) : boolean;
  247. {If list L is empty and the first node has been allocated, sets up the
  248.  pointers. Assumes that the node has been allocated with dlGrabMemory.
  249.  Returns a function value of false if the list is not empty.}
  250.   var
  251.     B1  : boolean;
  252.   begin
  253.     B1 := slFirstNode(slList(L), slNodePtr(P));
  254.     if B1 then
  255.       P^.Prev := nil;
  256.     dlFirstNode := B1;
  257.     end; {dlFirstNode}
  258.  
  259. {******************INITIALIZATION ROUTINES************************}
  260.  
  261. procedure slListInit(var L  : slList; RecSize : word);     
  262. {Initializes a singly linked list.}
  263.   begin
  264.     with L do begin
  265.       DataRecSize := RecSize;
  266.       Count := 0;
  267.       Head := nil;
  268.       Tail := nil;
  269.       Current := nil;
  270.       end; {with}
  271.     end; {slListInit}
  272.  
  273. procedure dlListInit(var L : dlList; RecSize : word);
  274. {Initializes a doubly linked list.}
  275.   begin
  276.     slListInit(slList(L), RecSize);
  277.     end; {dlListInit}
  278.  
  279. {******************STORAGE ROUTINES************************}
  280.  
  281. function slPush(var L : slList; var DataRec) : boolean;
  282. {Pushes a data record onto the top of the list.}
  283.   var
  284.     P : slNodePtr;
  285.   begin
  286.     if not slGrabMemory(L, P, DataRec) then begin
  287.       slPush := false;
  288.       exit;
  289.       end;
  290.     slPush := true;
  291.     if not slFirstNode(L, P) then begin
  292.       P^.Next := L.Head;
  293.       L.Head := P;
  294.       end;
  295.     inc(L.Count);
  296.     end; {slPush}
  297.  
  298. function dlPush(var L : dlList; var DataRec) : boolean;
  299. {Pushes a data record onto the top of the list.}
  300.   var
  301.     P : dlNodePtr;
  302.   begin
  303.     if not dlGrabMemory(L, P, DataRec) then begin
  304.       dlPush := false;
  305.       exit;
  306.       end;
  307.     dlPush := true;
  308.     if not dlFirstNode(L, P) then begin
  309.       P^.Next := L.Head;
  310.       L.Head^.Prev := P;
  311.       L.Head := P;
  312.       L.Head^.Prev := nil;
  313.       end;
  314.     inc(L.Count);
  315.     end; {dlPush}
  316.  
  317. function slAppend(var L : slList; var DataRec) : boolean;
  318. {Appends a data record to the tail of the list.}
  319.   var
  320.     P : slNodePtr;
  321.   begin
  322.     if not slGrabMemory(L, P, DataRec) then begin
  323.       slAppend := false;
  324.       exit;
  325.       end;
  326.     slAppend := true;
  327.     if not slFirstNode(L, P) then begin
  328.       L.Tail^.Next := P;
  329.       L.Tail := P;
  330.       L.Tail^.Next := nil;
  331.       end;
  332.     inc(L.Count);
  333.     end; {slAppend}
  334.  
  335. function dlAppend(var L : dlList; var DataRec) : boolean;
  336. {Appends a data record to the tail of the list.}
  337.   var
  338.     P : dlNodePtr;
  339.   begin
  340.     if not dlGrabMemory(L, P, DataRec) then begin
  341.       dlAppend := false;
  342.       exit;
  343.       end;
  344.     dlAppend := true;
  345.     if not dlFirstNode(L, P) then begin
  346.       L.Tail^.Next := P;
  347.       P^.Prev := L.Tail;
  348.       L.Tail := P;
  349.       L.Tail^.Next := nil;
  350.       end;
  351.     inc(L.Count);
  352.     end; {dlAppend}
  353.  
  354. function slPut(var L : slList; var DataRec) : boolean;
  355. {Inserts a data record following the current node; returns with current
  356.  pointer directed to the new node.}
  357.   var
  358.     P,
  359.     C : slNodePtr;
  360.   begin
  361.     if not slGrabMemory(L, P, DataRec) then begin
  362.       slPut := false;
  363.       exit;
  364.       end;
  365.     slPut := true;
  366.     C := L.Current;
  367.     if not slFirstNode(L, P) then begin
  368.       L.Current^.Next := C^.Next;
  369.       C^.Next := L.Current;
  370.       end;
  371.     if L.Current^.Next = nil then
  372.       L.Tail := L.Current;
  373.     inc(L.Count);
  374.     end; {slPut}
  375.  
  376. function dlPut(var L : dlList; var DataRec) : boolean;
  377. {Inserts a data record following the current node; returns with current
  378.  pointer directed to the new node.}
  379.   var
  380.     P,
  381.     C : dlNodePtr;
  382.   begin
  383.     if not dlGrabMemory(L, P, DataRec) then begin
  384.       dlPut := false;
  385.       exit;
  386.       end;
  387.     dlPut := true;
  388.     C := L.Current;
  389.     if not dlFirstNode(L, P) then begin
  390.       L.Current^.Next := C^.Next;
  391.       C^.Next := L.Current;
  392.       L.Current^.Prev := C;
  393.       L.Current^.Next^.Prev := L.Current;
  394.       end;
  395.     if L.Current^.Next = nil then
  396.       L.Tail := L.Current;
  397.     inc(L.Count);
  398.     end; {dlPut}
  399.  
  400. function dlPutPrev(var L : dlList; var DataRec) : boolean;
  401. {Inserts a data record ahead of the current node; returns with current
  402.  pointer directed to the new node.}
  403.   var
  404.     P,
  405.     C : dlNodePtr;
  406.   begin
  407.     if not dlGrabMemory(L, P, DataRec) then begin
  408.       dlPutPrev := false;
  409.       exit;
  410.       end;
  411.     dlPutPrev := true;
  412.     C := L.Current;
  413.     if not dlFirstNode(L, P) then begin
  414.       L.Current^.Prev := C^.Prev;
  415.       C^.Prev := L.Current;
  416.       L.Current^.Next := C;
  417.       L.Current^.Prev^.Next := L.Current;
  418.       end;
  419.     if L.Current^.Prev = nil then
  420.       L.Head := L.Current;
  421.     inc(L.Count);
  422.     end; {dlPutPrev}
  423.  
  424. function dlPutSorted(var L : dlList;
  425.                         var DataRec; Less : dlLessFunc) : boolean;
  426. {Inserts a data record into the list in sorted order, as determined by
  427.  the user-defined boolean function LESS.}
  428.   var
  429.     DataRec0  : pointer;
  430.   begin
  431.     if L.Count = 0 then begin                 {Empty list}
  432.       dlPutSorted := dlPut(L, DataRec);
  433.       exit;
  434.       end;
  435.     if not GetMemCheck(DataRec0, L.DataRecSize) then begin
  436.       dlPutSorted := false;
  437.       exit;
  438.       end;
  439.     if not dlGetCurrent(L, DataRec0^) then begin
  440.       if dlGetLast(L, DataRec0^) then ;
  441.       if Less(DataRec0^, DataRec) then begin
  442.         dlPutSorted := dlAppend(L, DataRec);
  443.         FreeMemCheck(DataRec0, L.DataRecSize);
  444.         exit;
  445.         end;
  446.       if dlGetFirst(L, DataRec0^) then ;
  447.       if not Less(DataRec0^, DataRec) then begin
  448.         dlPutSorted := dlPush(L, DataRec);
  449.         FreeMemCheck(DataRec0, L.DataRecSize);
  450.         exit;
  451.         end;
  452.       end; {if not dlGetCurrent}
  453.     if Less(DataRec0^, DataRec) then begin
  454.       while dlGetNext(L, DataRec0^) and Less(DataRec0^, DataRec) do ;
  455.       if not Less(DataRec0^, DataRec) then begin
  456.         dlPutSorted := dlPutPrev(L, DataRec);
  457.         end
  458.       else begin
  459.         dlPutSorted := dlAppend(L, DataRec);
  460.         end
  461.       end {if Less}
  462.     else begin
  463.       while dlGetPrev(L, DataRec0^) and not Less(DataRec0^, DataRec) do ;
  464.       if Less(DataRec0^, DataRec) then
  465.         dlPutSorted := dlPut(L, DataRec)
  466.       else
  467.         dlPutSorted := dlPush(L, DataRec);
  468.       end; {else}
  469.     FreeMemCheck(DataRec0, L.DataRecSize);
  470.     end; {dlPutSorted}
  471.  
  472. procedure slFree(var L : slList);
  473. {Releases the heap space allocated for a list and re-initializes the
  474.  list.}
  475.   var
  476.     T1  : LongInt;
  477.     P   : slNodePtr;
  478.   begin
  479.     for T1 := 1 to L.Count do begin
  480.       P := L.Head;
  481.       L.Head := P^.Next;
  482.       FreeMemCheck(P^.Data, L.DataRecSize);
  483.       FreeMemCheck(P, SizeOf(slNode));
  484.       end;
  485.     slListInit(L, L.DataRecSize);
  486.     end; {slFree}
  487.  
  488. procedure dlFree(var L : dlList);
  489. {Releases the heap space allocated for a list and re-initializes the
  490.  list.}
  491.   var
  492.     T1  : LongInt;
  493.     P   : dlNodePtr;
  494.   begin
  495.     for T1 := 1 to L.Count do begin
  496.       P := L.Head;
  497.       L.Head := P^.Next;
  498.       FreeMemCheck(P^.Data, L.DataRecSize);
  499.       FreeMemCheck(P, SizeOf(dlNode));
  500.       end;
  501.     dlListInit(L, L.DataRecSize);
  502.     end; {dlFree}
  503.  
  504. {******************RETRIEVAL ROUTINES************************}
  505.  
  506. function slGetCurrent(var L : slList; var DataRec) : boolean;
  507. {Returns the data record at the current node and does not move the node
  508.  pointer. Returns a function value of false if the list is empty or the
  509.  current node pointer is nil.}
  510.   begin
  511.     if L.Current = nil then begin
  512.       slGetCurrent := false;
  513.       exit;
  514.       end;
  515.     slGetCurrent := true;
  516.     Move(L.Current^.Data^, DataRec, L.DataRecSize);
  517.     end; {slGetCurrent}
  518.  
  519. function dlGetCurrent(var L : dlList; var DataRec) : boolean;
  520. {Returns the data record at the current node and does not move the node
  521.  pointer. Returns a function value of false if the list is empty or the
  522.  current node pointer is nil.}
  523.   var
  524.     S : slList absolute L;
  525.   begin
  526.     dlGetCurrent := slGetCurrent(S, DataRec);
  527.     end; {dlGetCurrent}
  528.  
  529. function slGetFirst(var L : slList; var DataRec) : boolean;
  530. {Returns the data record at the head of the list. Sets the current node
  531.  pointer to the head of the list. Returns a function value of false if
  532.  the list is empty.}
  533.   begin
  534.     L.Current := L.Head;
  535.     slGetFirst := slGetCurrent(L, DataRec);
  536.     end; {slGetFirst}
  537.  
  538. function dlGetFirst(var L : dlList; var DataRec) : boolean;
  539. {Returns the data record at the head of the list. Sets the current node
  540.  pointer to the head of the list. Returns a function value of false if
  541.  the list is empty.}
  542.   var
  543.     S : slList absolute L;
  544.   begin
  545.     dlGetFirst := slGetFirst(S, DataRec);
  546.     end; {dlGetFirst}
  547.  
  548. function slGetLast(var L : slList; var DataRec) : boolean;
  549. {Returns the data record at the tail of the list. Sets the current node
  550.  pointer to the tail of the list. Returns a function value of false if
  551.  the list is empty.}
  552.   begin
  553.     L.Current := L.Tail;
  554.     slGetLast := slGetCurrent(L, DataRec);
  555.     end; {slGetLast}
  556.  
  557. function dlGetLast(var L : dlList; var DataRec) : boolean;
  558. {Returns the data record at the tail of the list. Sets the current node
  559.  pointer to the tail of the list. Returns a function value of false if
  560.  the list is empty.}
  561.   var
  562.     S : slList absolute L;
  563.   begin
  564.     dlGetLast := slGetLast(S, DataRec);
  565.     end; {dlGetLast}
  566.  
  567. function slGetNext(var L :slList; var DataRec) : boolean;
  568. {Returns the next data record in the list. Sets the current node pointer
  569.  to the record retrieved. Returns a function value of false if the list is
  570.  empty or if the last record successfully retrieved was at the list tail.
  571.  In this case, calling slGetNext again will retrieve the head of the list.}
  572.   begin
  573.     if not (L.Count = 0) then begin
  574.       if L.Current = nil then
  575.         L.Current := L.Head
  576.       else
  577.         L.Current := L.Current^.Next;
  578.       end; {if not L.Count}
  579.     slGetNext := slGetCurrent(L, DataRec);
  580.     end; {slGetNext}
  581.  
  582. function dlGetNext(var L : dlList; var DataRec) : boolean;
  583. {Returns the next data record in the list. Sets the current node pointer
  584.  to the record retrieved. Returns a function value of false if the list is
  585.  empty or if the last record successfully retrieved was at the list tail.
  586.  In this case, calling dlGetNext again will retrieve the head of the list.}
  587.   var
  588.     S : slList absolute L;
  589.   begin
  590.     dlGetNext := slGetNext(S, DataRec);
  591.     end; {dlGetNext}
  592.  
  593. function dlGetPrev(var L : dlList; var DataRec) : boolean;
  594. {Same as dlGetNext, but in the opposite direction.}
  595.   begin
  596.     if not (L.Count = 0) then begin
  597.       if L.Current = nil then
  598.         L.Current := L.Tail
  599.       else
  600.         L.Current := L.Current^.Prev;
  601.       end; {if not L.Count}
  602.     dlGetPrev := dlGetCurrent(L, DataRec);
  603.     end; {dlGetPrev}
  604.  
  605. function slPop(var L : slList; var DataRec) : boolean;
  606. {Returns the data record at the head of the list, then deallocates the
  607.  space associated with the data record and node. Returns a function value
  608.  of false if the list is empty.}
  609.   var
  610.     P : slNodePtr;
  611.     B : boolean;
  612.   begin
  613.     B := slGetFirst(L, DataRec);
  614.     slPop := B;
  615.     if not B then exit;
  616.     P := L.Head;
  617.     L.Head := P^.Next;
  618.     L.Current := L.Head;
  619.     FreeMemCheck(P^.Data, L.DataRecSize);
  620.     FreeMemCheck(P, SizeOf(slNode));
  621.     dec(L.Count);
  622.     end; {slPop}
  623.  
  624. function dlPop(var L : dlList; var DataRec) : boolean;
  625. {Returns the data record at the head of the list, then deallocates the
  626.  space associated with the data record and node. Returns a function value
  627.  of false if the list is empty.}
  628.   var
  629.     P : dlNodePtr;
  630.     B : boolean;
  631.   begin
  632.     B := dlGetFirst(L, DataRec);
  633.     dlPop := B;
  634.     if not B then exit;
  635.     P := L.Head;
  636.     L.Head := P^.Next;
  637.     L.Head^.Prev := nil;
  638.     L.Current := L.Head;
  639.     FreeMemCheck(P^.Data, L.DataRecSize);
  640.     FreeMemCheck(P, SizeOf(dlNode));
  641.     dec(L.Count);
  642.     end; {dlPop}
  643.  
  644. {******************GENERAL UTILITY ROUTINES************************}
  645.  
  646. function slCount(L : slList) : LongInt;
  647. {Returns the number of records currently in the list.}
  648.   begin
  649.     slCount := L.Count;
  650.     end; {slCount}
  651.  
  652. function dlCount(L : dlList) : LongInt;
  653. {Returns the number of records currently in the list.}
  654.   begin
  655.     dlCount := L.Count;
  656.     end; {dlCount}
  657.  
  658. function slSpaceUsed(L : slList) : LongInt;
  659. {Returns the total amount of heap space currently allocated to the list.}
  660.   begin
  661.     slSpaceUsed := L.Count * (L.DataRecSize + SizeOf(slNode));
  662.     end; {slSpaceUsed}
  663.  
  664. function dlSpaceUsed(L : dlList) : LongInt;
  665. {Returns the total amount of heap space currently allocated to the list.}
  666.   begin
  667.     dlSpaceUsed := L.Count * (L.DataRecSize + SizeOf(dlNode));
  668.     end; {dlSpaceUsed}
  669.   end.
  670.